package com.mit.facade;

import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

import com.mit.common.RequestContext;
import com.mit.common.ResultContext;
import com.mit.common.exception.BaseException;
import com.mit.common.exception.InappropriateDefinitionException;
import com.mit.common.security.dto.UserDTO;

public class BusinessFacade {
	private Logger logger = Logger.getLogger(BusinessFacade.class);
	
	public ResultContext doBusiness(RequestContext req) throws BaseException {
		ResultContext result = new ResultContext();
		
		String beanId = req.getBeanId();
		String methodName = req.getMethodName();
		UserDTO currentUser = req.getUser();
		
		if(currentUser == null){
			String err = "User Info is not found in the RequestContext!";
			logger.error(err);
			throw new InappropriateDefinitionException(err);
		}
		
		if(StringUtils.isEmpty(beanId)){
			String msg = "BeanId can not be NULL";
			logger.error(msg);
			throw new InappropriateDefinitionException(msg);
		}
		if(StringUtils.isEmpty(methodName)){
			String msg = "MethodName can not be NULL";
			logger.error(msg);
			throw new InappropriateDefinitionException(msg);
		}
		

		try{
			Object bean = BeanHelper.getInstance().getBean(beanId);
			Class[] argsType = {RequestContext.class};
			Object[] args = {req};
			result = (ResultContext) invoke(bean, methodName, argsType, args);
		}catch(BaseException e){	
			// print full exception stack trace 
			logger.error("BaseException occurred: ", e);
			throw e;
		}catch(Exception e){
			// print full exception stack trace 
			logger.error("Exception occurred: ", e);
			if(e.getCause() != null){
				logger.error(e.getCause());
			}else{
				logger.error(e);
			}
			throw new BaseException(e.getMessage(), e);
		}
		
		return result;
		
	}

	private Object invoke(Object target, String methodName, Class[] argsType, Object[] args) throws Exception{
		Object rtn = null;
		Method method = null;
		
		try{
			method = target.getClass().getMethod(methodName, argsType);
			rtn = method.invoke(target, args);
		}catch(InvocationTargetException e){
			Throwable t = e.getTargetException();
			logger.error(t);
			if(t instanceof BaseException){
				throw new BaseException(t);
			}else if(t instanceof Exception){
				throw new Exception(t);
			}else{
				ByteArrayOutputStream ot = new ByteArrayOutputStream();
				t.printStackTrace(new PrintStream(ot));
				throw new Exception(ot.toString());
			}
		}finally{
			
		}
		return rtn;
		
	}
}
